public with sharing class Flickr {
    private final String USER_ID = '27635906@N03'; // This is the user id for 'weesilmania'. Yes, that's me;)

    public class Packet{
        private String key = 'Your API key should go here';
        
        private String header =     '<s:Envelope' +
                                    ' xmlns:s="http://www.w3.org/2003/05/soap-envelope"' +
                                    ' xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"'+
                                    ' xmlns:xsd="http://www.w3.org/1999/XMLSchema">'+
                                    '<s:Body>'+
                                    '      <x:FlickrRequest xmlns:x="urn:flickr">';
                                    
        private String footer =     '           <api_key>'+key+'</api_key>'+
                                    '      </x:FlickrRequest>'+
                                    '</s:Body>'+
                                    '</s:Envelope>';
                                
        public Map<String,String> argumentMap{get;set;}
        
        public Packet(){
            argumentMap = new Map<String,String>();
        }
        
        private String buildPacket(){
            String packet = header;
            
            for(String argument: argumentMap.keyset()){
                packet += '<'+argument+'>';
                packet += argumentMap.get(argument);
                packet += '</'+argument+'>';
            }
            
            packet += footer;
            
            return packet;
        }
        
        public String toXmlString(){
            return buildPacket();
        }
    }
    
    public String makeRequest(Map<String,String> argumentMap){
        Httprequest request = new HttpRequest();
        request.setMethod('POST');
        request.setEndpoint('http://api.flickr.com/services/soap/');
        
        Packet p = new Packet();
        p.argumentMap = argumentMap;
        
        request.setBody(p.toXmlString());
        
        Http http = new Http();
        
        HttpResponse response;
        
        try{
            response = http.send(request); 
        } catch (System.Exception e){
            System.debug(e);
            sendEmail(e.getMessage());
            return null;
        }
        
        System.debug(response.getBody());
        
        XmlStreamReader reader = response.getXmlStreamReader();
        
        reader.setCoalescing(true);
        
        try{
            while(reader.hasNext()){
                System.debug('packet localname: ' +reader.getLocalName());
                if(reader.isStartElement()&&reader.getLocalName()=='FlickrResponse'){
                    System.debug('here');
                    reader.next();
                    // This next step is a hack. For some reason everything within the FlickrResponse node is being escaped!
                    // i.e. '<' becomes &lt; ergo this hack. It's not cool, and if you know why please please please tell me.
                    if(reader.isCharacters()){
                        System.debug('text: '+reader.getText());
                        return reader.getText();
                        
                    }
                }       
    
                reader.next();
            }
        } catch (System.exception e){
            System.debug(e);           
            sendEmail(e.getMessage()); 
        }
        
        return null;
    }
    
    public FlickrUser getUserByEmail(String email){
        Map<String,String> arguments = new Map<String,String>();
        
        arguments.put('find_email',email);
        arguments.put('method','flickr.people.findByEmail');
        
        String response = makeRequest(arguments);
        System.debug(response);
        
        XmlStreamReader reader = new XmlStreamReader(response);
        FlickrUser user = new FlickrUser();
        user.email = email;
        
        while(reader.hasNext()){
            if(reader.isStartElement()){
                if(reader.getLocalName()=='user'){
                    Integer numAttributes = reader.getAttributeCount();
                    
                    for(Integer i = 0; i<numAttributes;i++){
                        if(reader.getAttributeLocalName(i)=='nsid'){
                            user.id = reader.getAttributeValueAt(i);
                        }
                    }
                } else if(reader.getLocalName()=='username'){
                    reader.next();
                    if(reader.hasText()){
                        user.username = reader.getText();
                    }
                }
            }   
        
            reader.next();
        }
        
        return user;
    }
    
    public class FlickrUser{
        public String email{get;set;}
        public String id{get;set;}
        public String username{get;set;}
    }    
    
    public List<PhotoSet> getPhotoSets(){ return getPhotoSets(USER_ID); }
    
    public List<PhotoSet> getPhotoSets(String userid) {
    
        List<PhotoSet> photoSets = new List<PhotoSet>();
        Map<String,String> arguments = new Map<String,String>();
        
        arguments.put('user_id',userid);
        arguments.put('method', 'flickr.photosets.getList');
        
        String response = makeRequest(arguments);
        System.debug('response: '+response);
        Xmlstreamreader reader = new Xmlstreamreader(response);
        
        //System.debug('Photoset XML: '+reader.toString());
        PhotoSet ps;
        
        while(reader.hasNext()){
            System.debug('EventType:'+reader.getEventType());
            System.debug('LocalName:'+reader.getLocalName());
            if(reader.hasText())
              System.debug('Text:'+reader.getText());               
            
            
            System.debug('1');
            if(reader.isStartElement()&&reader.getLocalName()=='photoset'){
                System.debug('2');
                ps = new PhotoSet();
            }
            System.debug('3');
            
            if(reader.isStartElement()){
                if(reader.getLocalName()=='photoset'){
                    System.debug('4');
                    
                    Integer numAttributes = reader.getAttributeCount();
                    
                    for(Integer i = 0; i<numAttributes;i++){
                        if(reader.getAttributeLocalName(i)=='id'){
                            String id = reader.getAttributeValueAt(i);
                            ps.id = id;
                        } else if(reader.getAttributeLocalName(i)=='photos'){
                            String numPhotos = reader.getAttributeValueAt(i);
                            ps.numPhotos = numPhotos;
                        }
                    }
                    
                }else if(reader.getLocalName()=='title'){
                    System.debug('title: '+reader.getEventType());
                    reader.next();
                    
                    String title = reader.getText();
                    System.debug('7');
                    ps.title = title;
                    System.debug('8');              
                }else if(reader.getLocalName()=='description'){
                    reader.next();
                    System.debug('9');
                    String description = reader.getText();
                    ps.description = description;
                    System.debug('10');
                }
            }
            System.debug('ps: '+ps);
            
            if(reader.isEndElement()&&reader.getLocalName()=='photoset'){
                photoSets.add(ps);
                System.debug('11');
            }
            
            reader.next();
        }
        
        return photoSets;
    }
    
    private class PhotoSet{
        public String id{get;set;}
        public String numPhotos{get;set;}
        public String title{get;set;}
        public String description{get;set;}
        
        public PhotoSet(){}
    }
    
    public List<Photo> photoSearch(String keywords){
        
        
        List<Photo> photos = new List<Photo>();
        Map<String,String> arguments = new Map<String,String>();
        
        arguments.put('method', 'flickr.photos.search');            
        arguments.put('text', keywords);
        arguments.put('per_page','10');
        arguments.put('extras','url_sq, url_t, url_s, url_m, url_o,owner_name');
        
        String response = makeRequest(arguments);
        System.debug(response);
        
        if(response==null){
            return null;
        }
        sendEmail('Search with keywords: '+keywords);
        
        XmlStreamReader reader = new XmlStreamReader(response);
        
        while(reader.hasNext()){
            if(reader.isStartElement()){
                Integer numAttributes = reader.getAttributeCount(); 
                if(reader.getLocalName()=='photo'){
                    Photo p = new Photo();
                    
                    for(Integer i = 0; i<numAttributes;i++){
                        String attributeName = reader.getAttributeLocalName(i); 
                        String attributeValue = reader.getAttributeValueAt(i);
                        
                        if(attributeName=='id')
                            p.id = attributeValue;
                        else if(attributeName=='title')
                            p.title = attributeValue;
                        else if(attributename=='server')
                            p.server = attributeValue;
                        else if(attributeName=='secret')
                            p.secret = attributeValue;
                        else if(attributeName=='ownername')
                        	p.owner = attributeValue;
                        else if(attributeName.startsWith('url'))
                            p.urls.put(attributeName,attributeValue);
                    }
                    
                    photos.add(p);
                }
            }
            reader.next();
        }
        
        return photos;
    }
    
    public List<Photo> getPhotosByPhotoSet(String psId){ return getPhotosByPhotoSet(psId, USER_ID);}
    
    public List<Photo> getPhotosByPhotoSet(String psId, String userid){
        List<Photo> photos = new List<Photo>();
        Map<String,String> arguments = new Map<String,String>();
        
        arguments.put('method', 'flickr.photosets.getPhotos');
        arguments.put('photoset_id',psId);
        arguments.put('user_id',userid);
        arguments.put('extras','url_sq, url_t, url_s, url_m, url_o,owner_name');
        
        String response = makeRequest(arguments);
        
        System.debug(response);
        
        if(response==null)
            return null;
            
        Xmlstreamreader reader = new Xmlstreamreader(response);
        
        while(reader.hasNext()){
            
            
            if(reader.isStartElement()){
                Integer numAttributes = reader.getAttributeCount(); 
                if(reader.getLocalName()=='photo'){
                    Photo p = new Photo();
                    
                    for(Integer i = 0; i<numAttributes;i++){
                        String attributeName = reader.getAttributeLocalName(i); 
                        String attributeValue = reader.getAttributeValueAt(i);
                        
                        if(attributeName=='id')
                            p.id = attributeValue;
                        else if(attributeName=='title')
                            p.title = attributeValue;
                    	else if(attributeName=='ownername')
                        	p.owner = attributeValue;
                        else if(attributeName.startsWith('url'))
                            p.urls.put(attributeName,attributeValue);
                    }
                    
                    photos.add(p);
                }               
            }
                        
            reader.next();
        }
        System.debug(photos);
        return photos;  
    }
    
    public class Photo extends GalleryImage{ 
        public String id{get;set;}
        public String secret{get;set;}
        public String server{get;set;}
        public Map<String,String> urls{get;set;}
        
        public Photo(){
            urls = new Map<String,String>();
        }
        
        public String getSquareUrl(){
            return urls.get('url_sq');
        }
        
        public String getTinyUrl(){
            return urls.get('url_t');
        }               
        
        public String getSmallUrl(){
            return urls.get('url_s');
        }
        
        public String getMedUrl(){
            return urls.get('url_m');
        }
        
        public String getLargeUrl(){
            return urls.get('url_l');
        }
        
        public override String getOriginalUrl(){ 
            return urls.get('url_o');
        }
        
        /** Overridden GalleryImage methods **/
        public override String getDisplayUrl(){
        	return getMedUrl(); 
        }
    }
    
    private void sendEmail(String msg){
        // Create a new single email message object 

        // that will send out a single email to the addresses in the To, CC & BCC list. 
            
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

        // Strings to hold the email addresses to which you are sending the email. 
            
        String[] toAddresses = new String[] {'wesley.nolte@telegraph.co.uk'}; 
          

        // Assign the addresses for the To and CC lists to the mail object. 
            
        mail.setToAddresses(toAddresses);


        // Specify the subject line for your email address. 
            
        mail.setSubject('Flickr Api Message');

        // Set to True if you want to BCC yourself on the email. 
            
        mail.setBccSender(false);

        // Optionally append the salesforce.com email signature to the email. 
            
        // The email address of the user executing the Apex Code will be used. 
            
        mail.setUseSignature(false);

        // Specify the text content of the email. 
            
        mail.setPlainTextBody(msg);
            
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

    }
    
    /**
        System.debug(getPhotoSets());
        System.debug(getPhotosByPhotoSet('72157605600725406')); 
        System.debug(getUserByEmail('weesmann@yahoo.com'));
        System.debug(photoSearch('london'));
    **/
}